#pragma once

/*
 * WeakCallback.
 */

#include <functional>
#include <memory>

namespace anet {
	namespace util {
		template<typename CLASS, typename... ARGS>
		class CWeakCallback {
		public:
			CWeakCallback(const std::weak_ptr<CLASS>& obj, const std::function<void(CLASS*, ARGS...)>& func)
				: m_objWeak(obj), m_func(func) {
			}
			virtual ~CWeakCallback() = default;

		public:
			void operator()(ARGS&&... args) const {
				std::shared_ptr<CLASS> shareObj(m_objWeak.lock());
				if (shareObj) {
					m_func(shareObj.get(), std::forward<ARGS>(args)...);
				}
			}

		private:
			std::weak_ptr<CLASS> m_objWeak;
			std::function<void(CLASS*, ARGS...)> m_func;
		};


		// CLASS's non-const member function.
		template<typename CLASS, typename... ARGS>
		CWeakCallback<CLASS, ARGS...> 
		makeWeakCallback(const std::shared_ptr<CLASS>& object, void (CLASS::*function)(ARGS...)) {
			return CWeakCallback<CLASS, ARGS...>(object, function);
		}

		// CLASS's const member function.
		template<typename CLASS, typename... ARGS>
		CWeakCallback<CLASS, ARGS...> 
		makeWeakCallback(const std::shared_ptr<CLASS>& object, void (CLASS::*function)(ARGS...) const) {
			return CWeakCallback<CLASS, ARGS...>(object, function);
		}
	} 
}